﻿using System;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Media;
using Microsoft.Xna.Framework.Content;
using System.Collections.Generic;
using System.Linq;

namespace PhysicsSimulator
{
    class AudioManager
    {
        #region Singleton
        /// <summary>
        /// The singleton for this type.
        /// </summary>
        private static AudioManager audioManager = null;
        #endregion

        #region Audio Data
        private SoundEffectInstance musicSound;
        private Dictionary<string, SoundEffectInstance> soundBank;
        private Dictionary<string, Song> songBank;
        private string[,] soundNames;
        private string[,] songNames;
        #endregion

        #region Initialization Methods

        ContentManager ContentManager;

        private AudioManager(ContentManager content)
        {
            ContentManager = content;
        }

        /// <summary>
        /// Initialize the static AudioManager functionality.
        /// </summary>
        /// <param name="game">The game that this component will be attached to.</param>
        public static void Initialize(ContentManager content)
        {

            audioManager = new AudioManager(content);
            audioManager.AddSounds();
            audioManager.soundBank = new Dictionary<string, SoundEffectInstance>();
            audioManager.songBank = new Dictionary<string, Song>();
        }

        public static int TotalItems
        {
            get
            {
                return audioManager.songNames.GetLength(0) + audioManager.soundNames.GetLength(0);
            }
        }
        #endregion

        #region Loading Methodes
        private void AddSounds()
        {
            audioManager.soundNames = new string[,] 
            {                  
                {"BoulderHit","BoulderHit"},
                {"CatapultExplosion","CatapultExplosion"},
                {"CatapultFire","CatapultFire"},
                {"Lose","Lose"},
                {"RopeStretch","RopeStretch"},
                {"Win","Win"},
                {"CandyMusic","CandyMusic"},
                {"CandyHit","candy-hit"},
            };
            audioManager.songNames = new string[,] 
            {                
            };
        }
        /// <summary>
        /// Loads a sounds and organizes them for future usage
        /// </summary>
        private static int _soundsIndex = 0;
        private static int _musicsIndex = 0;
        public static void LoadSounds()
        {
            string soundLocation = "Sounds/";
            while (_soundsIndex < audioManager.soundNames.GetLength(0))
            {
                SoundEffect se = audioManager.ContentManager.Load<SoundEffect>(
                    soundLocation + audioManager.soundNames[_soundsIndex, 1]);

                audioManager.soundBank.Add(
                    audioManager.soundNames[_soundsIndex, 0], se.CreateInstance());

                Dictionary<string, SoundEffectInstance> a = audioManager.soundBank;

                _soundsIndex++;
                Microsoft.Xna.Framework.FrameworkDispatcher.Update();

            }

            while (_musicsIndex < audioManager.songNames.GetLength(0))
            {
                Song song = audioManager.ContentManager.Load<Song>(soundLocation + audioManager.songNames[_musicsIndex, 1]);

                audioManager.songBank.Add(audioManager.songNames[_musicsIndex, 0], song);
                _musicsIndex++;
                Microsoft.Xna.Framework.FrameworkDispatcher.Update();
            }
        }
        #endregion

        public static SoundEffectInstance getSoundEffectInstance(string fileName)
        {
            if (audioManager.soundBank.ContainsKey(fileName))
            {
                return audioManager.soundBank[fileName];
            }
            return null;
        }

        #region Sound Methods
        /// <summary>
        /// Plays a sound by name.
        /// </summary>
        /// <param name="soundName">The name of the sound to play</param>
        public static void PlaySound(string soundName)
        {
            // If the sound exists, start it
            //if (!CSettings.EnabledSounds)
            //    return;
            Dictionary<String, SoundEffectInstance> a = audioManager.soundBank;

            if (audioManager.soundBank.ContainsKey(soundName))
            {
                if (audioManager.soundBank[soundName].State != SoundState.Stopped)
                {
                    audioManager.soundBank[soundName].Stop(true);
                    System.Threading.Thread.Sleep(1);
                }


                audioManager.soundBank[soundName].Play();


            }
        }

        public static void PlaySong(string songName, bool isLoop)
        {
            //if (!CSettings.EnabledSounds)
            //    return;
            if (audioManager.songBank.ContainsKey(songName))
                if (MediaPlayer.GameHasControl)
                {
                    MediaPlayer.IsRepeating = isLoop;
                    MediaPlayer.Play(audioManager.songBank[songName]);
                }
        }
        public static void StopSong()
        {
            if (MediaPlayer.GameHasControl)
                MediaPlayer.Stop();
        }

        public static void PauseSong()
        {
            if (MediaPlayer.GameHasControl)
                MediaPlayer.Pause();
        }
        public static void ResumeSong()
        {
            if (MediaPlayer.GameHasControl)
                MediaPlayer.Resume();
        }
        /// <summary>
        /// Plays a sound by name.
        /// </summary>
        /// <param name="soundName">The name of the sound to play</param>
        /// <param name="isLooped">Indicates if the sound should loop</param>
        public static void PlaySound(string soundName, bool isLooped)
        {
            //if (!CSettings.EnabledSounds)
            //    return;
            // If the sound exists, start it
            if (audioManager.soundBank.ContainsKey(soundName))
            {
                if (audioManager.soundBank[soundName].IsLooped != isLooped)
                    audioManager.soundBank[soundName].IsLooped = isLooped;

                if (audioManager.soundBank[soundName].State != SoundState.Stopped)
                {
                    audioManager.soundBank[soundName].Stop(true);
                }
                audioManager.soundBank[soundName].Play();
            }
        }

        public static SoundState GetSoundState(string soundName)
        {
            if (audioManager.soundBank.ContainsKey(soundName))
                return audioManager.soundBank[soundName].State;
            return SoundState.Stopped;
        }

        /// <summary>
        /// Stops a sound mid-play. If the sound is not playing, this
        /// method does nothing.
        /// </summary>
        /// <param name="soundName">The name of the sound to stop</param>
        public static void StopSound(string soundName)
        {
            // If the sound exists, stop it

            if (audioManager.soundBank.ContainsKey(soundName))
                audioManager.soundBank[soundName].Stop();
        }

        /// <summary>
        /// Stops a sound mid-play. If the sound is not playing, this
        /// method does nothing.
        /// </summary>
        /// <param name="soundName">The name of the sound to stop</param>
        public static void StopSounds()
        {
            var soundEffectInstances = from sound in audioManager.soundBank.Values
                                       where sound.State != SoundState.Stopped
                                       select sound;

            foreach (var soundeffectInstance in soundEffectInstances)
                soundeffectInstance.Stop();
        }

        /// <summary>
        /// Pause or Resume all sounds to support pause screen
        /// </summary>
        /// <param name="isPause">Should pause or resume?</param>
        public static void PauseResumeSounds(bool isPause)
        {

            SoundState state = isPause ? SoundState.Paused : SoundState.Playing;

            var soundEffectInstances = from sound in audioManager.soundBank.Values
                                       where sound.State == state
                                       select sound;

            foreach (var soundeffectInstance in soundEffectInstances)
            {
                if (isPause)
                    soundeffectInstance.Play();
                else
                    soundeffectInstance.Pause();
            }
        }
        /// <summary>
        /// Play music by sound name.
        /// </summary>
        /// <param name="musicSoundName">The name of the music sound</param>
        public static void PlayMusic(string musicSoundName)
        {

            // Stop the old music sound
            if (audioManager.musicSound != null)
                audioManager.musicSound.Stop(true);

            // If the music sound exists
            if (audioManager.soundBank.ContainsKey(musicSoundName))
            {
                // Get the instance and start it
                audioManager.musicSound = audioManager.soundBank[musicSoundName];
                if (!audioManager.musicSound.IsLooped)
                    audioManager.musicSound.IsLooped = true;
                audioManager.musicSound.Play();
            }
        }
        #endregion

        #region Instance Disposal Methods
        /// <summary>
        /// Clean up the component when it is disposing.
        /// </summary>
        protected void Dispose(bool disposing)
        {
            try
            {
                if (disposing)
                {
                    foreach (var item in soundBank)
                    {
                        item.Value.Dispose();
                    }
                    soundBank.Clear();
                    soundBank = null;
                    songBank.Clear();
                    songBank = null;
                }
            }
            finally
            {
                audioManager = null;
            }
        }
        #endregion
    }
}
